﻿// ------------------------------------------------------------------------
// 项目名称：Canroc.Net 
// 版权归属：Canroc（https://gitee.com/canroc）
//
// 许可证信息
// Canroc.Net项目主要遵循 Apache 许可证（版本 2.0）进行分发和使用。许可证位于源代码树根目录中的 LICENSE-APACHE 文件。
//
// 使用条款：
// 1.使用本项目应遵守相关法律法规和许可证的要求。
// 2.不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动。
// 3.任何基于本项目二次开发而产生的一切法律纠纷和责任，我们不承担任何责任
//
// 免责声明
// 对于因使用本代码而产生的任何直接、间接、偶然、特殊或后果性损害，我们不承担任何责任。
//
// 其他重要信息
// Canroc.Net 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。
// ------------------------------------------------------------------------

using Canroc.Net.Application.SysMenuService.Dto;

// ReSharper disable once CheckNamespace
namespace Canroc.Net.Application.SysMenuService;

/// <summary>
///     系统菜单应用服务
/// </summary>
[ApiDescriptionSettings("System")]
public class SysMenuAppService(
    SqlSugarRepository<SysMenu> menuRep,
    IServiceProvider serviceProvider) : IDynamicApiController, ITransient
{
    /// <summary>
    ///     添加系统菜单
    /// </summary>
    /// <param name="data">表单数据</param>
    /// <returns></returns>
    public async Task<bool> AdditionAsync(MenuInput data)
    {
        var entity = data.Adapt<SysMenu>();
        return await menuRep.InsertAsync(entity);
    }

    /// <summary>
    ///     编辑系统菜单
    /// </summary>
    /// <param name="data">表单数据</param>
    /// <returns></returns>
    public async Task<bool> EditAsync(MenuInput data)
    {
        var entity = await menuRep.GetByIdAsync(data.Id);
        // 更新数据
        data.Adapt(entity);
        return await menuRep.UpdateAsync(entity);
    }

    /// <summary>
    ///     编辑系统菜单状态
    /// </summary>
    /// <param name="data">请求参数</param>
    /// <returns></returns>
    public async Task<bool> EnableAsync(InputModel data)
    {
        return await menuRep.UpdateAsync(m => new SysMenu { IsEnable = SqlFunc.IIF(m.IsEnable, false, true) },
            m => m.Id == data.Id);
    }

    /// <summary>
    ///     删除系统菜单
    /// </summary>
    /// <param name="data">请求参数</param>
    /// <returns></returns>
    public async Task<bool> DelAsync(DeleteInputModel data)
    {
        return await menuRep.UpdateAsync(m => new SysMenu { IsDelete = true }, m => data.Ids.Contains(m.Id));
    }

    /// <summary>
    ///     获取系统菜单
    /// </summary>
    /// <param name="id">主键</param>
    /// <returns></returns>
    public async Task<MenuOutput?> GetDataAsync(Guid id)
    {
        return await menuRep.AsQueryable().Where(m => m.Id == id).Select<MenuOutput>().FirstAsync();
    }

    /// <summary>
    ///     获取系统菜单列表
    /// </summary>
    /// <param name="query">查询参数</param>
    /// <returns></returns>
    public async Task<List<MenuOutput>?> GetTreeAsync([FromQuery] MenuQuery query)
    {
        return await menuRep
            .AsQueryable()
            .WhereIF(!query.Title.IsNullOrEmpty(), m => m.Title.Contains(query.Title))
            .WhereIF(query.IsEnable.HasValue, m => m.IsEnable == query.IsEnable)
            .OrderBy(m => new { m.Sort, m.CreateTime })
            .Select<MenuOutput>()
            .ToTreeAsync(m => m.Children, m => m.Pid, Guid.Empty, m => m.Id);
    }

    /// <summary>
    ///     获取系统菜单选项
    /// </summary>
    /// <returns></returns>
    public async Task<List<CascaderOptionOutputModel>?> GetCascaderOptionAsync()
    {
        return await menuRep
            .AsQueryable()
            .Where(m => m.IsEnable && m.MenuType != MenuTypeEnum.Button)
            .OrderBy(m => m.Sort)
            .ToCascaderOptionTreeAsync(m => m.Id, m => m.Pid, m => m.Title, Guid.Empty, m => m.Sort);
    }

    #region 内部函数

    /// <summary>
    ///     获取系统用户所拥有的菜单
    /// </summary>
    /// <param name="userId">用户Id</param>
    /// <param name="isAllMenu">是否查询全部菜单</param>
    /// <returns></returns>
    [NonAction]
    public async Task<List<MenuOutput>?> GetUserMenuAsync(Guid userId, bool isAllMenu = false)
    {
        List<MenuOutput> menus;
        if (isAllMenu)
        {
            menus = await menuRep
                .AsQueryable()
                .Where(m => m.IsEnable && m.MenuType != MenuTypeEnum.Button)
                .Select<MenuOutput>()
                .OrderBy(m => m.Sort)
                .ToTreeAsync(m => m.Children, m => m.Pid, Guid.Empty, m => m.Id);
        }
        else
        {
            var roleAndMenuRep = serviceProvider.GetRequiredService<SqlSugarRepository<RelRoleMenu>>();
            menus = await roleAndMenuRep
                .AsQueryable()
                .LeftJoin<RelRoleUser>((irm, iru) => irm.RoleId == iru.RoleId)
                .LeftJoin<SysMenu>((irm, iru, m) => irm.MenuId == m.Id)
                .Where((irm, iru, m) => iru.UserId == userId &&
                                        m.IsEnable &&
                                        m.MenuType != MenuTypeEnum.Button)
                .Distinct()
                .Select<MenuOutput>()
                .MergeTable()
                .OrderBy(m => m.Sort)
                .ToTreeAsync(m => m.Children, m => m.Pid, Guid.Empty, m => m.Id);
        }

        return menus;
    }

    /// <summary>
    ///     获取系统用户所拥有的按钮
    /// </summary>
    /// <param name="userId">用户Id</param>
    /// <param name="isAllMenu">是否查询全部菜单</param>
    /// <returns></returns>
    public async Task<Dictionary<string, List<string>>> GetUserButtonAsync(Guid userId, bool isAllMenu = false)
    {
        Dictionary<string, List<string>> buttons = [];
        List<SysMenu> sysMenus;
        List<SysMenu> sysButtons;

        if (isAllMenu)
        {
            sysMenus = await menuRep.GetListAsync(m => m.IsEnable && m.MenuType == MenuTypeEnum.Menu);
            sysButtons = await menuRep.GetListAsync(m => m.IsEnable && m.MenuType == MenuTypeEnum.Button);
        }
        else
        {
            var roleAndMenuRep = serviceProvider.GetRequiredService<SqlSugarRepository<RelRoleMenu>>();
            sysMenus = await roleAndMenuRep
                .AsQueryable()
                .LeftJoin<RelRoleUser>((irm, iru) => irm.RoleId == iru.RoleId)
                .LeftJoin<SysMenu>((irm, iru, m) => irm.MenuId == m.Id)
                .Where((irm, iru, m) => iru.UserId == userId &&
                                        m.IsEnable &&
                                        m.MenuType == MenuTypeEnum.Menu)
                .Distinct()
                .Select((irm, iru, m) => m)
                .ToListAsync();
            sysButtons = await roleAndMenuRep
                .AsQueryable()
                .LeftJoin<RelRoleUser>((irm, iru) => irm.RoleId == iru.RoleId)
                .LeftJoin<SysMenu>((irm, iru, m) => irm.MenuId == m.Id)
                .Where((irm, iru, m) => iru.UserId == userId &&
                                        m.IsEnable &&
                                        m.MenuType == MenuTypeEnum.Button)
                .Distinct()
                .Select((irm, iru, m) => m)
                .ToListAsync();
        }

        // 组装按钮
        foreach (var menu in sysMenus)
        {
            var buttonList = sysButtons.Where(b => b.Pid == menu.Id).Select(b => b.Name).ToList();
            buttons.Add(menu.Name, buttonList);
        }

        return buttons;
    }

    #endregion
}